package net.wicp.tams.common.binlog.self;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import net.wicp.tams.common.apiext.ByteUtil;
import net.wicp.tams.common.apiext.PwdUtil;

public abstract class MysqlUtil {
	// private static final BigDecimal POSITIVE_ONE = BigDecimal.ONE;
	// private static final BigDecimal NEGATIVE_ONE = new BigDecimal("-1");

	private static final int[] DIG_TO_BYTES = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4 };
	private static final int DIG_PER_DEC = 9;

	/**
	 * mysql密码格式
	 */

	public static byte[] password41OrLater(byte password[], byte scramble[]) {
		final byte[] stage1 = PwdUtil.sha(password);
		final byte[] stage2 = PwdUtil.sha(ByteUtil.concat(scramble, PwdUtil.sha(stage1)));
		return ByteUtil.xor(stage1, stage2);
	}

	/**
	 * 
	 */
	public static int toYear(int value) {
		return 1900 + value;
	}

	public static java.sql.Date toDate(int value) {
		final int d = value % 32;
		value >>>= 5;
		final int m = value % 16;
		final int y = value >> 4;
		final Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(y, m - 1, d);
		return new java.sql.Date(cal.getTimeInMillis());
	}

	public static java.sql.Time toTime(int value) {
		final int s = (int) (value % 100);
		value /= 100;
		final int m = (int) (value % 100);
		final int h = (int) (value / 100);
		final Calendar c = Calendar.getInstance();
		c.set(1970, 0, 1, h, m, s);
		c.set(Calendar.MILLISECOND, 0);
		return new java.sql.Time(c.getTimeInMillis());
	}

	public static java.sql.Time toTime2(int value, int nanos) {
		final int h = (value >> 12) & 0x3FF;
		final int m = (value >> 6) & 0x3F;
		final int s = (value >> 0) & 0x3F;
		final Calendar c = Calendar.getInstance();
		c.set(1970, 0, 1, h, m, s);
		c.set(Calendar.MILLISECOND, 0);
		final long millis = c.getTimeInMillis();
		return new java.sql.Time(millis + (nanos / 1000000));
	}

	public static java.util.Date toDatetime(long value) {
		final int second = (int) (value % 100);
		value /= 100;
		final int minute = (int) (value % 100);
		value /= 100;
		final int hour = (int) (value % 100);
		value /= 100;
		final int day = (int) (value % 100);
		value /= 100;
		final int month = (int) (value % 100);
		final int year = (int) (value / 100);
		final Calendar c = Calendar.getInstance();
		c.set(year, month - 1, day, hour, minute, second);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTime();
	}

	public static java.util.Date toDatetime2(long value, int nanos) {
		final long x = (value >> 22) & 0x1FFFFL;
		final int year = (int) (x / 13);
		final int month = (int) (x % 13);
		final int day = ((int) (value >> 17)) & 0x1F;
		final int hour = ((int) (value >> 12)) & 0x1F;
		final int minute = ((int) (value >> 6)) & 0x3F;
		final int second = ((int) (value >> 0)) & 0x3F;
		final Calendar c = Calendar.getInstance();
		c.set(year, month - 1, day, hour, minute, second);
		c.set(Calendar.MILLISECOND, 0);
		final long millis = c.getTimeInMillis();
		return new java.util.Date(millis + (nanos / 1000000));
	}

	public static java.sql.Timestamp toTimestamp(long seconds) {
		return new java.sql.Timestamp(seconds * 1000L);
	}

	public static Timestamp toTimestamp2(long seconds, int nanos) {
		final java.sql.Timestamp r = new java.sql.Timestamp(seconds * 1000L);
		r.setNanos(nanos);
		return r;
	}

	public static BigDecimal toDecimal(int precision, int scale, byte[] value) {
		boolean positive = (value[0] & 0x80) == 0x80;
		value[0] ^= 0x80;
		if (!positive) {
			for (int i = 0; i < value.length; i++) {
				value[i] ^= 0xFF;
			}
		}
		int x = precision - scale;
		int ipDigits = x / DIG_PER_DEC;
		int ipDigitsX = x - ipDigits * DIG_PER_DEC;
		int ipSize = (ipDigits << 2) + DIG_TO_BYTES[ipDigitsX];
		int offset = DIG_TO_BYTES[ipDigitsX];
		BigDecimal ip = offset > 0 ? BigDecimal.valueOf(bigEndianInteger(value, 0, offset)) : BigDecimal.ZERO;
		for (; offset < ipSize; offset += 4) {
			int i = bigEndianInteger(value, offset, 4);
			ip = ip.movePointRight(DIG_PER_DEC).add(BigDecimal.valueOf(i));
		}
		int shift = 0;
		BigDecimal fp = BigDecimal.ZERO;
		for (; shift + DIG_PER_DEC <= scale; shift += DIG_PER_DEC, offset += 4) {
			int i = bigEndianInteger(value, offset, 4);
			fp = fp.add(BigDecimal.valueOf(i).movePointLeft(shift + DIG_PER_DEC));
		}
		if (shift < scale) {
			int i = bigEndianInteger(value, offset, DIG_TO_BYTES[scale - shift]);
			fp = fp.add(BigDecimal.valueOf(i).movePointLeft(scale));
		}
		BigDecimal result = ip.add(fp);
		return positive ? result : result.negate();
	}

	private static int bigEndianInteger(byte[] bytes, int offset, int length) {
		int result = 0;
		for (int i = offset; i < (offset + length); i++) {
			byte b = bytes[i];
			result = (result << 8) | (b >= 0 ? (int) b : (b + 256));
		}
		return result;
	}

	/**
	 * 
	 */
	public static int getDecimalBinarySize(int precision, int scale) {
		final int x = precision - scale;
		int ipd = x / DIG_PER_DEC, fpd = scale / DIG_PER_DEC;
		int decimalLength = (ipd << 2) + DIG_TO_BYTES[x - ipd * DIG_PER_DEC] + (fpd << 2)
				+ DIG_TO_BYTES[scale - fpd * DIG_PER_DEC];
		return decimalLength;
	}

	/***
	 * 比较2个gtid的大小
	 * 
	 * @param gtid1
	 * @param gtid2
	 * @return
	 */
	public static int compareMulti(String gtid1, String gtid2) {
		Map<String, String> map1 = new HashMap<>();
		Map<String, String> map2 = new HashMap<>();
		for (String hostgitd : gtid1.split(",")) {
			String[] argtemp = hostgitd.split(":");
			map1.put(argtemp[0], argtemp[1]);
		}
		for (String hostgitd : gtid2.split(",")) {
			String[] argtemp = hostgitd.split(":");
			map2.put(argtemp[0], argtemp[1]);
		}

		for (String key : map1.keySet()) {
			String[] tempval1 = map1.get(key).split("-");
			String[] tempval2 = map2.get(key).split("-");
			String maxval1 = tempval1.length > 1 ? tempval1[1] : tempval1[0];
			String maxval2 = tempval2.length > 1 ? tempval2[1] : tempval2[0];
			if (!maxval1.equals(maxval2)) {
				return Integer.parseInt(maxval1) - Integer.parseInt(maxval2);
			}
		}
		return 0;
	}

	public static int compare(String gtid1, String gtid2) {
		return Integer.parseInt(gtid1.split(":")[1]) - Integer.parseInt(gtid2.split(":")[1]);
	}
}
